package com.aipanda.entity;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang.StringUtils;
import org.dom4j.io.SAXReader;
import org.hibernate.search.annotations.Analyzer;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.Store;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;
import org.springframework.core.io.ClassPathResource;
import org.wltea.analyzer.lucene.IKAnalyzer;

import com.aipanda.util.FKUtils;

@Indexed//标示需要建立全文索引的实体类
@Entity
@Table(name = "aipanda_article")
public class Article extends BaseEntity {
	private static final long serialVersionUID = 1475773294701585482L;
	public static final String HITS_CACHE_NAME = "articleHits";
	public static final int HITS_CACHE_INTERVAL = 600000;
	private static final Pattern pattern = Pattern.compile("[,;\\.!?，；。！？]");
	private static String staticPath;
	private String title;
	private String author;
	private String content;
	private String seoTitle;
	private String seoKeywords;
	private String seoDescription;
	private Boolean isPublication;
	private Boolean isTop;
	private Long hits;
	private Integer pageNumber;
	private ArticleCategory articleCategory;
	private Set<Tag> tags = new HashSet<Tag>();

	static {
		try {
			File file = new ClassPathResource("/aipanda.xml").getFile();
			org.dom4j.Document document = new SAXReader().read(file);
			org.dom4j.Element element = (org.dom4j.Element) document.selectSingleNode("/aipanda/template[@id='articleContent']");
			staticPath = element.attributeValue("staticPath");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * <p>@Field:标注哪些域是可搜索的。</p>
	 * <p>name用于标示Field的名称</p>
	 * <p>store用于标示这个属性的内容是否需要保存在索引中</p>
	 * <p>index属性标示该字段属性是否进行分词index=Index.TOKENIZED参数说明可以通过Analyzer解析</p>
	 * <p>analyzer用于标示建立索引时所使用的分析器是什么类，这里使用IKAnalyzer</p>
	 * @return
	 */
	@Field(store = Store.YES, index = Index.TOKENIZED, analyzer = @Analyzer(impl = IKAnalyzer.class))
	@NotEmpty
	@Length(max = 255)
	@Column(nullable = false)
	public String getTitle() {
		return this.title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	@Field(store = Store.YES, index = Index.NO)
	@Length(max = 255)
	public String getAuthor() {
		return this.author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	@Field(store = Store.YES, index = Index.TOKENIZED, analyzer = @Analyzer(impl = IKAnalyzer.class))
	@Lob
	public String getContent() {
		if (this.pageNumber != null) {
			String[] pageContents = getPageContents();
			if (this.pageNumber < 1){
				this.pageNumber = 1;
			}
			if (this.pageNumber > pageContents.length){
				this.pageNumber = pageContents.length;
			}
			return pageContents[(this.pageNumber - 1)];
		}
		return this.content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	@Length(max = 255)
	@Column(name="seo_title")
	public String getSeoTitle() {
		return this.seoTitle;
	}

	public void setSeoTitle(String seoTitle) {
		this.seoTitle = seoTitle;
	}

	@Length(max = 255)
	@Column(name="seo_keywords")
	public String getSeoKeywords() {
		return this.seoKeywords;
	}

	public void setSeoKeywords(String seoKeywords) {
		if (seoKeywords != null)
			seoKeywords = seoKeywords.replaceAll("[,\\s]*,[,\\s]*", ",")
					.replaceAll("^,|,$", "");
		this.seoKeywords = seoKeywords;
	}

	@Length(max = 255)
	@Column(name="seo_description")
	public String getSeoDescription() {
		return this.seoDescription;
	}

	public void setSeoDescription(String seoDescription) {
		this.seoDescription = seoDescription;
	}

	@Field(store = Store.YES, index = Index.UN_TOKENIZED)
	@NotNull
	@Column(name="is_publication",nullable = false)
	public Boolean getIsPublication() {
		return this.isPublication;
	}

	public void setIsPublication(Boolean isPublication) {
		this.isPublication = isPublication;
	}

	@Field(store = Store.YES, index = Index.UN_TOKENIZED)
	@NotNull
	@Column(name="is_top",nullable = false)
	public Boolean getIsTop() {
		return this.isTop;
	}

	public void setIsTop(Boolean isTop) {
		this.isTop = isTop;
	}

	@Column(nullable = false)
	public Long getHits() {
		return this.hits;
	}

	public void setHits(Long hits) {
		this.hits = hits;
	}

	@Transient
	public Integer getPageNumber() {
		return this.pageNumber;
	}

	@Transient
	public void setPageNumber(Integer pageNumber) {
		this.pageNumber = pageNumber;
	}

	@NotNull
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name="article_category",nullable = false)
	public ArticleCategory getArticleCategory() {
		return this.articleCategory;
	}

	public void setArticleCategory(ArticleCategory articleCategory) {
		this.articleCategory = articleCategory;
	}
	
	@ManyToMany(fetch = FetchType.LAZY)
	@JoinTable(name = "aipanda_article_tag",joinColumns ={@JoinColumn(name="articles",nullable=false)},inverseJoinColumns = {@JoinColumn(name="tags",nullable=false)})
	@OrderBy("order asc")
	public Set<Tag> getTags() {
		return tags;
	}

	public void setTags(Set<Tag> tags) {
		this.tags = tags;
	}

	@Transient
	public String getPath() {
		Map<String,Object> hashMap = new HashMap<String,Object>();
		hashMap.put("id", getId());
		hashMap.put("createDate", getCreateDate());
		hashMap.put("modifyDate", getModifyDate());
		hashMap.put("title", getTitle());
		hashMap.put("seoTitle", getSeoTitle());
		hashMap.put("seoKeywords", getSeoKeywords());
		hashMap.put("seoDescription", getSeoDescription());
		hashMap.put("pageNumber", getPageNumber());
		hashMap.put("articleCategory", getArticleCategory());
		return FKUtils.process(staticPath, hashMap);
	}

	@Transient
	public String getText() {
		if (getContent() != null){
			return Jsoup.parse(getContent()).text();
		}
		return null;
	}

	@Transient
	public String[] getPageContents() {
		if (StringUtils.isEmpty(this.content)){
			return new String[] { "" };
		}
		if (this.content.contains("<hr class=\"pageBreak\" />"))
			return this.content.split("<hr class=\"pageBreak\" />");
		List<String> arrayList = new ArrayList<String>();
		Document document = Jsoup.parse(this.content);
		List<Node> list = document.body().childNodes();
		if (list != null) {
			int i = 0;
			StringBuffer sb = new StringBuffer();
			Iterator<Node> iterator = list.iterator();
			while (iterator.hasNext()) {
				Node node = iterator.next();
				if (node instanceof Element) {
					Element element = (Element)node;
					sb.append(element.outerHtml());
					i += element.text().length();
					if (i < 800){
						continue;
					}
					arrayList.add(sb.toString());
					i = 0;
					sb.setLength(0);
				} else {
					if (!(node instanceof TextNode)){
						continue;
					}
					TextNode	textNode = (TextNode) node;
					String text = textNode.text();
					String[] strs = pattern.split(text);
					Matcher matcher = pattern.matcher(text);
					for (String str : strs) {
						if (matcher.find()){
							str = str + matcher.group();
						}
						sb.append(str);
						i += str.length();
						if (i < 800){
							continue;
						}
						arrayList.add(sb.toString());
						i = 0;
						sb.setLength(0);
					}
				}
			}
			String str = sb.toString();
			if (StringUtils.isNotEmpty(str)){
				arrayList.add(str);
			}
		}
		return arrayList.toArray(new String[arrayList.size()]);
	}

	@Transient
	public int getTotalPages() {
		return getPageContents().length;
	}
}

